#version 450 core

layout (location = 0) out vec4 o_Color;
//out int o_EntityID;

struct VertexOutput
{
	vec4 Color;
	vec2 TexCoord;
	float TilingFactor;
	vec2 UV;
};

layout (location = 0) in VertexOutput Output;
layout (location = 4) in float v_TexIndex;
layout (location = 5) in flat int v_EntityID;

uniform mediump vec2 TextureSize0;
uniform lowp float Time; 

uniform sampler2D u_Textures[5];

#define S(a, b, t) smoothstep(a, b, t)
//#define CHEAP_NORMALS
//#define HAS_HEART
#define USE_POST_PROCESSING

vec3 N13(float p) {
    //  from DAVE HOSKINS
   vec3 p3 = fract(vec3(p) * vec3(.1031,.11369,.13787));
   p3 += dot(p3, p3.yzx + 19.19);
   return fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));
}

vec4 N14(float t) {
	return fract(sin(t*vec4(123., 1024., 1456., 264.))*vec4(6547., 345., 8799., 1564.));
}
float N(float t) {
    return fract(sin(t*12345.564)*7658.76);
}

float Saw(float b, float t) {
	return S(0., b, t)*S(1., b, t);
}


vec2 DropLayer2(vec2 uv, float t) {
    vec2 UV = uv;
    
    uv.y += t*0.75;
    vec2 a = vec2(6., 1.);
    vec2 grid = a*2.;
    vec2 id = floor(uv*grid);
    
    float colShift = N(id.x); 
    uv.y += colShift;
    
    id = floor(uv*grid);
    vec3 n = N13(id.x*35.2+id.y*2376.1);
    vec2 st = fract(uv*grid)-vec2(.5, 0);
    
    float x = n.x-.5;
    
    float y = UV.y*20.;
    float wiggle = sin(y+sin(y));
    x += wiggle*(.5-abs(x))*(n.z-.5);
    x *= .7;
    float ti = fract(t+n.z);
    y = (Saw(.85, ti)-.5)*.9+.5;
    vec2 p = vec2(x, y);
    
    float d = length((st-p)*a.yx);
    
    float mainDrop = S(.4, .0, d);
    
    float r = sqrt(S(1., y, st.y));
    float cd = abs(st.x-x);
    float trail = S(.23*r, .15*r*r, cd);
    float trailFront = S(-.02, .02, st.y-y);
    trail *= trailFront*r*r;
    
    y = UV.y;
    float trail2 = S(.2*r, .0, cd);
    float droplets = max(0., (sin(y*(1.-y)*120.)-st.y))*trail2*trailFront*n.z;
    y = fract(y*10.)+(st.y-.5);
    float dd = length(st-vec2(x, y));
    droplets = S(.3, 0., dd);
    float m = mainDrop+droplets*r*trailFront;
    
    //m += st.x>a.y*.45 || st.y>a.x*.165 ? 1.2 : 0.;
    return vec2(m, trail);
}

float StaticDrops(vec2 uv, float t) {
	uv *= 40.;
    
    vec2 id = floor(uv);
    uv = fract(uv)-.5;
    vec3 n = N13(id.x*107.45+id.y*3543.654);
    vec2 p = (n.xy-.5)*.7;
    float d = length(uv-p);
    
    float fade = Saw(.025, fract(t+n.z));
    float c = S(.3, 0., d)*fract(n.z*10.)*fade;
    return c;
}

vec2 Drops(vec2 uv, float t, float l0, float l1, float l2) {
    float s = StaticDrops(uv, t)*l0; 
    vec2 m1 = DropLayer2(uv, t)*l1;
    vec2 m2 = DropLayer2(uv*1.85, t)*l2;
    
    float c = s+m1.x+m2.x;
    c = S(.3, 1., c);
    
    return vec2(c, max(m1.y*l0, m2.y*l1));
}

vec4 gaussianBlur(mediump vec2 coord, lowp vec2 dir, sampler2D colorTexture)
{
    // Defines the one-dimensional Gaussian Kernel with 9 samples.
    float GAUSSIAN_KERNEL[9];
    GAUSSIAN_KERNEL[0] = 0.028532;
    GAUSSIAN_KERNEL[1] = 0.067234;
    GAUSSIAN_KERNEL[2] = 0.124009;
    GAUSSIAN_KERNEL[3] = 0.179044;
    GAUSSIAN_KERNEL[4] = 0.20236;
    GAUSSIAN_KERNEL[5] = 0.179044;
    GAUSSIAN_KERNEL[6] = 0.124009;
    GAUSSIAN_KERNEL[7] = 0.067234;
    GAUSSIAN_KERNEL[8] = 0.028532;

    vec2 texel = 1.0/TextureSize0;
    vec4 sum = vec4(0.0);
    // Get the original texture coordinate for this fragment.
    vec2 tc = coord;
    // Get the amount to blur.
    float blur = 2.0;
    // Set the amount of blur in the horizontal direction.
    float hstep = dir.x*texel.x;
    // Set the amount of blur in the vertical direction.
    float vstep = dir.y*texel.y;

    // Sample the texture 9 times for every fragment.
    for(int i = 0; i < 9; i++)
    {
        float pixelOffset = (float(i) - floor(9.0 * 0.5));
        mediump vec2 coord = vec2(tc.x + pixelOffset * blur * hstep, tc.y + pixelOffset * blur * vstep);
        sum += texture2D(colorTexture, coord) * GAUSSIAN_KERNEL[i];
    }

    return sum;
}

void main()
{
	vec4 texColor = Output.Color;
    vec2 uv = Output.TexCoord * Output.TilingFactor;

	switch(int(v_TexIndex))
	{
		//case  0: texColor *= texture(u_Textures[0], uv); break;
	}

    //float ratio = TextureSize0.x / TextureSize0.y;
    //uv = uv * 2.0 - 1.0;
    //uv.x *= ratio;    
    
    vec2 UV = uv;
    vec3 iMouse = vec3(0.0, 0.0, 0.0);
    //vec3 M = iMouse.xyz/iResolution.xyz;
    vec3 M = iMouse.xyz/vec3(TextureSize0.x, TextureSize0.y, 1.0);
    float T = -Time;//+M.x*2.;
    
    #ifdef HAS_HEART
        T = mod(Time, 102.);
        //T = mix(T, M.x*102., M.z>0.?1.:0.);
    #endif

    float t = T*.2;
    
    float rainAmount = iMouse.z>0. ? M.y : sin(T*.05)*.3+.7;
    
    float maxBlur = mix(3., 6., rainAmount);
    float minBlur = 2.;
    
    float story = 0.;
    float heart = 0.;
    
    #ifdef HAS_HEART
        story = S(0., 70., T);
        
        t = min(1., T/70.);						// remap drop time so it goes slower when it freezes
        t = 1.-t;
        t = (1.-t*t)*70.;
        
        float zoom= mix(.3, 1.2, story);		// slowly zoom out
        uv *=zoom;
        minBlur = 4.+S(.5, 1., story)*3.;		// more opaque glass towards the end
        maxBlur = 6.+S(.5, 1., story)*1.5;
        
        vec2 hv = uv-vec2(.0, -.1);				// build heart
        hv.x *= .5;
        float s = S(110., 70., T);				// heart gets smaller and fades towards the end
        hv.y-=sqrt(abs(hv.x))*.5*s;
        heart = length(hv);
        heart = S(.4*s, .2*s, heart)*s;
        rainAmount = heart;						// the rain is where the heart is
        
        maxBlur-=heart;							// inside the heart slighly less foggy
        uv *= 1.5;								// zoom out a bit more
        t *= .25;
    #else
        float zoom = -cos(T*.2);
        //uv *= .7+zoom*.3;
    #endif
    //UV = (UV-.5)*(.9+zoom*.1)+.5;
    
    float staticDrops = S(-.5, 1., rainAmount)*2.;
    float layer1 = S(.25, .75, rainAmount);//big rain
    float layer2 = S(.0, .5, rainAmount);
    
    
    vec2 c = Drops(uv, t, staticDrops, layer1, layer2);
   #ifdef CHEAP_NORMALS
    	vec2 n = vec2(dFdx(c.x), dFdy(c.x));// cheap normals (3x cheaper, but 2 times shittier ;))
    #else
    	vec2 e = vec2(.001, 0.);
    	float cx = Drops(uv+e, t, staticDrops, layer1, layer2).x;
    	float cy = Drops(uv+e.yx, t, staticDrops, layer1, layer2).x;
    	vec2 n = vec2(cx-c.x, cy-c.x);		// expensive normals
    #endif
    
    
    #ifdef HAS_HEART
        n *= 1.-S(60., 85., T);
        c.y *= 1.-S(80., 100., T)*.8;
    #endif
    
    //float focus = mix(maxBlur-c.y, minBlur, S(.1, .2, c.x));
    //vec3 col = textureLod(u_Textures[0], UV+n, focus).rgb;
    //vec4 col = texture(u_Textures[0], UV+n);    

    vec4 col = texture(u_Textures[0], UV+n); //+n   
    //vec4 col = gaussianBlur(UV, vec2(1.0, 1.0), u_Textures[0]); //+n   

    
    #ifdef USE_POST_PROCESSING
        //t = (T+3.)*.5;										// make time sync with first lightnoing
        //float colFade = sin(t*.2)*.5+.5+story;
        //col *= mix(vec4(1.), vec4(.8, .9, 1.3, 1.), colFade);	// subtle color shift
        //col *= mix(vec4(1.), vec4(1., 1., 1., 1.), colFade);	// subtle color shift
        //float fade = S(0., 10., T);							// fade in at the start
        // lightning = sin(t*sin(t*10.));				// lighting flicker
        //lightning *= pow(max(0., sin(t+sin(t))), 10.);		// lightning flash
        //col *= 1.+lightning*fade*mix(1., .1, story*story);	// composite lightning
        //col *= 1.-dot(UV-=.5, UV);							// vignette
                                                    
        #ifdef HAS_HEART
            col = mix(pow(col, vec3(1.2)), col, heart);
            fade *= S(102., 97., T);
        #endif
        
        //col *= fade;										// composite start and end fade
    #endif

    texColor.rgb = col.rgb + vec3(0.01);
    texColor.a = 1.0;

	o_Color = texColor;
	//o_Color = vec4(n.x, n.y, 0.0, 1.0);
}
